package com.such.kit.database.bean;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.such.kit.database.dialect.TypeFactory;
import com.such.kit.database.support.DDLBean;
import com.such.kit.easyparam.ParamMap;
import com.such.kit.placeholder.PlaceholderCommons;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;

/**
 * @作者 SUCH
 * @日期 2017-9-12 下午1:50:55
 * @描述 DDL 表对象
 */
public class DDLTable extends DDLBean<DatabaseTable> {

	private static final long serialVersionUID = 6191067383805316424L;

	private String schema;
	private String tableName;
	private String tableType;
	private String tableComment;

	// 表信息扩展
	private List<DDLColumn> columns = new ArrayList<DDLColumn>();
	private List<DDLPrimaryKey> primaryKeys = new ArrayList<DDLPrimaryKey>();
	private List<DDLForeignKey> foreignKeys = new ArrayList<DDLForeignKey>();
	private List<DDLIndex> indexs = new ArrayList<DDLIndex>();
	private String changedTableName;

	public DDLTable() {
		
	}

	public DDLTable(DatabaseTable table) {
		converter(table);
	}

	public String getSchema() {
		return this.schema;
	}

	public void setSchema(String schema) {
		this.schema = schema;
	}

	public String getTableName() {
		return this.tableName;
	}

	public void setTableName(String tableName) {
		this.tableName = tableName;
	}

	public String getTableType() {
		return this.tableType;
	}

	public void setTableType(String tableType) {
		this.tableType = tableType;
	}

	public String getTableComment() {
		return this.tableComment;
	}

	public void setTableComment(String tableComment) {
		this.tableComment = tableComment;
	}

	public List<DDLColumn> getColumns() {
		return this.columns;
	}

	public void setColumns(List<DDLColumn> columns) {
		this.columns = columns;
	}

	public List<DDLPrimaryKey> getPrimaryKeys() {
		return this.primaryKeys;
	}

	public void setPrimaryKeys(List<DDLPrimaryKey> primaryKeys) {
		this.primaryKeys = primaryKeys;
	}

	public List<DDLForeignKey> getForeignKeys() {
		return this.foreignKeys;
	}

	public void setForeignKeys(List<DDLForeignKey> foreignKeys) {
		this.foreignKeys = foreignKeys;
	}

	public List<DDLIndex> getIndexs() {
		return this.indexs;
	}

	public void setIndexs(List<DDLIndex> indexs) {
		this.indexs = indexs;
	}

	public void addColumn(DDLColumn column) {
		this.columns.add(column);
	}

	public void addPrimaryKey(DDLPrimaryKey primaryKey) {
		this.primaryKeys.add(primaryKey);
	}

	public void addForeignKey(DDLForeignKey foreignKey) {
		this.foreignKeys.add(foreignKey);
	}

	public void addIndex(DDLIndex index) {
		this.indexs.add(index);
	}

	public String getChangedTableName() {
		return this.changedTableName;
	}

	public void setChangedTableName(String changedTableName) {
		this.changedTableName = changedTableName;
	}

	public void converter(DatabaseTable table) {
		if (ValidateCommons.isNotEmpty(table)) {
			setSchema(table.getSchema());
			setTableName(table.getName());
			setTableType(table.getType());
			setTableComment(table.getComment());

			List<DatabaseColumn> columns = table.getColumns();
			if (ValidateCommons.isNotEmpty(columns)) {
				for (DatabaseColumn column : columns) {
					addColumn(new DDLColumn(column));
				}
			}

			Map<String, List<DatabasePrimaryKey>> primaryKeysMap = DDLPrimaryKey.grouping(table.getPrimaryKeys());
			if (ValidateCommons.isNotEmpty(primaryKeysMap)) {
				for (List<DatabasePrimaryKey> primaryKeys : primaryKeysMap.values()) {
					addPrimaryKey(new DDLPrimaryKey(primaryKeys));
				}
			}

			Map<String, List<DatabaseForeignKey>> foreignKeysMap = DDLForeignKey.grouping(table.getForeignKeys());
			if (ValidateCommons.isNotEmpty(foreignKeysMap)) {
				for (List<DatabaseForeignKey> foreignKeys : foreignKeysMap.values()) {
					addForeignKey(new DDLForeignKey(foreignKeys));
				}
			}

			Map<String, List<DatabaseIndex>> indexsMap = DDLIndex.grouping(table.getIndexs());
			if (ValidateCommons.isNotEmpty(indexsMap)) {
				for (List<DatabaseIndex> indexs : indexsMap.values()) {
					addIndex(new DDLIndex(indexs));
				}
			}
		}
	}

	public Map<String, String> buildRendererParams(Map<String, String> resourceKeyMapping, Map<String, String> ddlTemplateMapping, Map<String, String> params, TypeFactory type) {
		String tableName = this.tableName;
		if (ValidateCommons.isNotEmpty(this.schema) && ValidateCommons.isNotEmpty(tableName)) {
			tableName = StringCommons.merger(this.schema, ".", tableName);
		}

		Map<String, String> tableParams = new HashMap<String, String>();
		if (ValidateCommons.isNotEmpty(params)) {
			tableParams.putAll(params);
		}
		putString("tableName", tableName, tableParams, resourceKeyMapping, ddlTemplateMapping);
		putString("tableComment", this.tableComment, tableParams, resourceKeyMapping, ddlTemplateMapping);
		putString("changedTableName", this.changedTableName, tableParams, resourceKeyMapping, ddlTemplateMapping);
		return tableParams;
	}

	/**
	 * <p>方法名：reset</p>
	 * <p>描述：参照映射表重置表信息</p>
	 * @param schemaRemap schema 映射
	 * @param tableNameRemap tableName 映射
	 * @param constraintNameRemap constraintName（约束名）映射，包括主键、外键
	 * @param indexNameRemap index 映射
	 */
	public void reset(Map<String, String> schemaRemap, Map<String, String> tableNameRemap, Map<String, String> constraintNameRemap, Map<String, String> indexNameRemap) {
		boolean schemaRemapable = ValidateCommons.isNotEmpty(schemaRemap);
		boolean tableNameRemapable = ValidateCommons.isNotEmpty(tableNameRemap);
		boolean constraintNameRemapable = ValidateCommons.isNotEmpty(constraintNameRemap);
		boolean indexNameRemapable = ValidateCommons.isNotEmpty(indexNameRemap);

		if (schemaRemapable) {
			setSchema(StringCommons.emptyValue(schemaRemap.get(this.schema), this.schema));
		}
		if (tableNameRemapable) {
			setTableName(StringCommons.emptyValue(tableNameRemap.get(this.tableName), this.tableName));
		}
		List<DDLColumn> columns = getColumns();
		if (ValidateCommons.isNotEmpty(columns) && (schemaRemapable || tableNameRemapable)) {
			for (DDLColumn column : columns) {
				if (schemaRemapable) {
					String schema = column.getSchema();
					column.setSchema(StringCommons.emptyValue(schemaRemap.get(schema), schema));
				}
				if (tableNameRemapable) {
					String tableName = column.getTableName();
					column.setTableName(StringCommons.emptyValue(tableNameRemap.get(tableName), tableName));
				}
			}
		}
		List<DDLPrimaryKey> primaryKeys = getPrimaryKeys();
		if (ValidateCommons.isNotEmpty(primaryKeys) && (schemaRemapable || tableNameRemapable)) {
			for (DDLPrimaryKey primaryKey : primaryKeys) {
				if (schemaRemapable) {
					String schema = primaryKey.getSchema();
					primaryKey.setSchema(StringCommons.emptyValue(schemaRemap.get(schema), schema));
				}
				if (tableNameRemapable) {
					String tableName = primaryKey.getTableName();
					primaryKey.setTableName(StringCommons.emptyValue(tableNameRemap.get(tableName), tableName));
				}
				if (constraintNameRemapable) {
					String pkName = primaryKey.getPkName();
					primaryKey.setPkName(StringCommons.emptyValue(constraintNameRemap.get(pkName), pkName));
				}
			}
		}
		List<DDLForeignKey> foreignKeys = getForeignKeys();
		if (ValidateCommons.isNotEmpty(foreignKeys) && (schemaRemapable || tableNameRemapable || constraintNameRemapable)) {
			for (DDLForeignKey foreignKey : foreignKeys) {
				if (schemaRemapable) {
					String fkSchema = foreignKey.getFkSchema();
					String referenceSchema = foreignKey.getReferenceSchema();
					foreignKey.setFkSchema(StringCommons.emptyValue(schemaRemap.get(fkSchema), fkSchema));
					foreignKey.setReferenceSchema(StringCommons.emptyValue(schemaRemap.get(referenceSchema), referenceSchema));
				}
				if (tableNameRemapable) {
					String fkTableName = foreignKey.getFkTableName();
					String referenceTableName = foreignKey.getReferenceTableName();
					foreignKey.setFkTableName(StringCommons.emptyValue(tableNameRemap.get(fkTableName), fkTableName));
					foreignKey.setReferenceTableName(StringCommons.emptyValue(tableNameRemap.get(referenceTableName), referenceTableName));
				}
				if (constraintNameRemapable) {
					String fkName = foreignKey.getFkName();
					String referenceName = foreignKey.getReferenceName();
					foreignKey.setFkName(StringCommons.emptyValue(constraintNameRemap.get(fkName), fkName));
					foreignKey.setReferenceName(StringCommons.emptyValue(constraintNameRemap.get(referenceName), referenceName));
				}
			}
		}
		List<DDLIndex> indexs = getIndexs();
		if (ValidateCommons.isNotEmpty(indexs) && (schemaRemapable || tableNameRemapable || indexNameRemapable)) {
			for (DDLIndex index : indexs) {
				if (schemaRemapable) {
					String schema = index.getSchema();
					index.setSchema(StringCommons.emptyValue(schemaRemap.get(schema), schema));
				}
				if (tableNameRemapable) {
					String tableName = index.getTableName();
					index.setTableName(StringCommons.emptyValue(tableNameRemap.get(tableName), tableName));
				}
				if (indexNameRemapable) {
					String indexName = index.getIndexName();
					index.setIndexName(StringCommons.emptyValue(tableNameRemap.get(indexName), indexName));
				}
			}
		}
	}

	/**
	 * <p>方法名：reset</p>
	 * <p>描述：参照表达式（占位符为 #[name]）重置表信息</p>
	 * @param schemaExpression schema 表达式
	 * @param tableNameExpression tableName 表达式
	 * @param constraintNameExpression constraintName（约束名）表达式，包括主键、外键
	 * @param indexNameExpression index 表达式
	 */
	public void reset(String schemaExpression, String tableNameExpression, String constraintNameExpression, String indexNameExpression) {
		boolean schemaRemapable = ValidateCommons.isNotEmpty(schemaExpression);
		boolean tableNameRemapable = ValidateCommons.isNotEmpty(tableNameExpression);
		boolean constraintNameRemapable = ValidateCommons.isNotEmpty(constraintNameExpression);
		boolean indexNameRemapable = ValidateCommons.isNotEmpty(indexNameExpression);

		if (schemaRemapable) {
			setSchema(PlaceholderCommons.replacePlaceholder(schemaExpression, new ParamMap<String, String>().putParam("name", this.schema)));
		}
		if (tableNameRemapable) {
			setTableName(PlaceholderCommons.replacePlaceholder(tableNameExpression, new ParamMap<String, String>().putParam("name", this.tableName)));
		}
		List<DDLColumn> columns = getColumns();
		if (ValidateCommons.isNotEmpty(columns) && (schemaRemapable || tableNameRemapable)) {
			for (DDLColumn column : columns) {
				if (schemaRemapable) {
					String schema = column.getSchema();
					column.setSchema(PlaceholderCommons.replacePlaceholder(schemaExpression, new ParamMap<String, String>().putParam("name", schema)));
				}
				if (tableNameRemapable) {
					String tableName = column.getTableName();
					column.setTableName(PlaceholderCommons.replacePlaceholder(tableNameExpression, new ParamMap<String, String>().putParam("name", tableName)));
				}
			}
		}
		List<DDLPrimaryKey> primaryKeys = getPrimaryKeys();
		if (ValidateCommons.isNotEmpty(primaryKeys) && (schemaRemapable || tableNameRemapable)) {
			for (DDLPrimaryKey primaryKey : primaryKeys) {
				if (schemaRemapable) {
					String schema = primaryKey.getSchema();
					primaryKey.setSchema(PlaceholderCommons.replacePlaceholder(schemaExpression, new ParamMap<String, String>().putParam("name", schema)));
				}
				if (tableNameRemapable) {
					String tableName = primaryKey.getTableName();
					primaryKey.setTableName(PlaceholderCommons.replacePlaceholder(tableNameExpression, new ParamMap<String, String>().putParam("name", tableName)));
				}
				if (constraintNameRemapable) {
					String pkName = primaryKey.getPkName();
					primaryKey.setPkName(PlaceholderCommons.replacePlaceholder(constraintNameExpression, new ParamMap<String, String>().putParam("name", pkName)));
				}
			}
		}
		List<DDLForeignKey> foreignKeys = getForeignKeys();
		if (ValidateCommons.isNotEmpty(foreignKeys) && (schemaRemapable || tableNameRemapable || constraintNameRemapable)) {
			for (DDLForeignKey foreignKey : foreignKeys) {
				if (schemaRemapable) {
					String fkSchema = foreignKey.getFkSchema();
					String referenceSchema = foreignKey.getReferenceSchema();
					foreignKey.setFkSchema(PlaceholderCommons.replacePlaceholder(schemaExpression, new ParamMap<String, String>().putParam("name", fkSchema)));
					foreignKey.setReferenceSchema(PlaceholderCommons.replacePlaceholder(schemaExpression, new ParamMap<String, String>().putParam("name", referenceSchema)));
				}
				if (tableNameRemapable) {
					String fkTableName = foreignKey.getFkTableName();
					String referenceTableName = foreignKey.getReferenceTableName();
					foreignKey.setFkTableName(PlaceholderCommons.replacePlaceholder(tableNameExpression, new ParamMap<String, String>().putParam("name", fkTableName)));
					foreignKey.setReferenceTableName(PlaceholderCommons.replacePlaceholder(tableNameExpression, new ParamMap<String, String>().putParam("name", referenceTableName)));
				}
				if (constraintNameRemapable) {
					String fkName = foreignKey.getFkName();
					String referenceName = foreignKey.getReferenceName();
					foreignKey.setFkName(PlaceholderCommons.replacePlaceholder(constraintNameExpression, new ParamMap<String, String>().putParam("name", fkName)));
					foreignKey.setReferenceName(PlaceholderCommons.replacePlaceholder(constraintNameExpression, new ParamMap<String, String>().putParam("name", referenceName)));
				}
			}
		}
		List<DDLIndex> indexs = getIndexs();
		if (ValidateCommons.isNotEmpty(indexs) && (schemaRemapable || tableNameRemapable || indexNameRemapable)) {
			for (DDLIndex index : indexs) {
				if (schemaRemapable) {
					String schema = index.getSchema();
					index.setSchema(PlaceholderCommons.replacePlaceholder(schemaExpression, new ParamMap<String, String>().putParam("name", schema)));
				}
				if (tableNameRemapable) {
					String tableName = index.getTableName();
					index.setTableName(PlaceholderCommons.replacePlaceholder(tableNameExpression, new ParamMap<String, String>().putParam("name", tableName)));
				}
				if (indexNameRemapable) {
					String indexName = index.getIndexName();
					index.setIndexName(PlaceholderCommons.replacePlaceholder(indexNameExpression, new ParamMap<String, String>().putParam("name", indexName)));
				}
			}
		}
	}

}
